
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Render Functions - vue.js</title>
        <meta charset="utf-8">
        <meta name="description" content="Vue.js - Intuitive, Fast and Composable MVVM for building interactive interfaces.">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Roboto Mono' rel='stylesheet' type='text/css'>
        <link href='//fonts.googleapis.com/css?family=Dosis:300,500&text=Vue.js' rel='stylesheet' type='text/css'>
        <link href="//cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" rel='stylesheet' type='text/css'>
        <link rel="icon" href="/images/logo.png" type="image/x-icon">
        <script>
            window.PAGE_TYPE = "guide"
        </script>
        <link rel="stylesheet" href="/css/page.css">
        <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-46852172-1', 'vuejs.org');
  ga('send', 'pageview');
</script>
        <script src="/js/vue.js"></script>
    </head>
    <body>
        <div id="mobile-bar">
            <a class="menu-button"></a>
            <a class="logo" href="/"></a>
        </div>
        
            <div id="header">
  <a id="logo" href="/">
    <img src="/images/logo.png">
    <span>Vue.js <sup>2.0 RC</sup></span>
  </a>
  <span style="
    position: absolute;
    top: 100%;
    left: 60px;
    padding: 0 10px;
    background: #ef9f00;
    border-radius: 3px;
    margin-top: -15px;
    line-height: 30px;
    color: white;
    font-weight: bold;
    letter-spacing: 1px;
    box-shadow: 0 1px 2px rgba(0,0,0,.3);
  ">
    WORK IN PROGRESS
  </span>
  <ul id="nav">
    <li>
  <form id="search-form">
    <input type="text" id="search-query-nav" class="search-query st-default-search-input">
  </form>
</li>
<li><a href="/guide/" class="nav-link current">Guide</a></li>
<li><a href="/api/" class="nav-link">API</a></li>
<li><a href="/examples/" class="nav-link">Examples</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li class="nav-dropdown-container">
  <a class="nav-link">Community</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="https://github.com/vuejs/vue" class="nav-link" target="_blank">GitHub</a></li>
    <li><a href="http://forum.vuejs.org" class="nav-link" target="_blank">Forum</a></li>
    <li><a href="https://gitter.im/vuejs/vue" class="nav-link" target="_blank">Chat</a></li>
    <li><a href="https://twitter.com/vuejs" class="nav-link" target="_blank">Twitter</a></li>
  </ul>
</li>


  </ul>
</div>

            <div id="main">
                
                    
    <div class="sidebar">
    <ul class="main-menu">
        <li>
  <form id="search-form">
    <input type="text" id="search-query-sidebar" class="search-query st-default-search-input">
  </form>
</li>
<li><a href="/guide/" class="nav-link current">Guide</a></li>
<li><a href="/api/" class="nav-link">API</a></li>
<li><a href="/examples/" class="nav-link">Examples</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li class="nav-dropdown-container">
  <a class="nav-link">Community</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="https://github.com/vuejs/vue" class="nav-link" target="_blank">GitHub</a></li>
    <li><a href="http://forum.vuejs.org" class="nav-link" target="_blank">Forum</a></li>
    <li><a href="https://gitter.im/vuejs/vue" class="nav-link" target="_blank">Chat</a></li>
    <li><a href="https://twitter.com/vuejs" class="nav-link" target="_blank">Twitter</a></li>
  </ul>
</li>


    </ul>
    <div class="list">
        <div id="donate" style="margin-bottom: 20px">
            <span class="wrapper" style="width: 110px">
              <img src="/images/patreon.png">
              <a href="/support-vuejs">Support Vue.js</a>
            </span>
        </div>
        <h2>
            Guide
            <select class="version-select">
                <option value="rc" selected>2.0</option>
                <!-- !!TODO: Update value to subdomain when 2.0 is released -->
                <option value="">1.0</option>
                <option>0.12</option>
                <option>0.11</option>
            </select>
        </h2>
        <ul class="menu-root">
            
                
                
                  <li><h3>Essentials</h3></li>
                
                
                
                <li>
                    <a href="/guide/installation.html" class="sidebar-link">Installation</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/index.html" class="sidebar-link">Introduction</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/instance.html" class="sidebar-link">The Vue Instance</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/syntax.html" class="sidebar-link">Template Syntax</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/computed.html" class="sidebar-link">Computed Properties and Watchers</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/class-and-style.html" class="sidebar-link">Class and Style Bindings</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/conditional.html" class="sidebar-link">Conditional Rendering</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/list.html" class="sidebar-link">List Rendering</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/events.html" class="sidebar-link">Event Handling</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/forms.html" class="sidebar-link">Form Input Bindings</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/components.html" class="sidebar-link">Components</a>
                </li>
            
                
                
                
                  <li><h3>Advanced</h3></li>
                
                
                <li>
                    <a href="/guide/transitions.html" class="sidebar-link">Transitions: Entering, Leaving, and Lists</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/transitioning-state.html" class="sidebar-link">Transitioning State</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/render-function.html" class="sidebar-link current">Render Functions</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/reactivity.html" class="sidebar-link">Reactivity in Depth</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/custom-directive.html" class="sidebar-link">Custom Directives</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/mixins.html" class="sidebar-link">Mixins</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/plugins.html" class="sidebar-link">Plugins</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/single-file-components.html" class="sidebar-link">Single File Components</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/routing.html" class="sidebar-link">Routing</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/state-management.html" class="sidebar-link">State Management</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/unit-testing.html" class="sidebar-link">Unit Testing</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/ssr.html" class="sidebar-link">Server-Side Rendering</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/migration.html" class="sidebar-link">Migration from 1.x</a>
                </li>
            
                
                
                
                
                  <li><h3>Meta</h3></li>
                
                <li>
                    <a href="/guide/comparison.html" class="sidebar-link">Comparison with Other Frameworks</a>
                </li>
            
                
                
                
                
                <li>
                    <a href="/guide/join.html" class="sidebar-link">Join the Vue.js Community!</a>
                </li>
            
        </ul>
    </div>
</div>


<div class="content guide with-sidebar render-function-guide">
    <div id="ad">
  <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=vuejs" id="_carbonads_js"></script>
</div>

    <h1>Render Functions</h1>
    <h2 id="Basics"><a href="#Basics" class="headerlink" title="Basics"></a>Basics</h2><p>Vue recommends using templates to build your HTML in the vast majority of cases. There are situations however, where you really need the full programmatic power of JavaScript. That’s where you can use the <strong>render  function</strong>, a closer-to-the-compiler alternative to templates.</p>
<p>Let’s dive into a simple example where a <code>render</code> function would be practical. Say you want to generate anchored headings:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">a</span> <span class="attr">name</span>=<span class="string">"hello-world"</span> <span class="attr">href</span>=<span class="string">"#hello-world"</span>&gt;</span></div><div class="line">    Hello world!</div><div class="line">  <span class="tag">&lt;/<span class="name">a</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">h1</span>&gt;</span></div></pre></td></tr></table></figure>
<p>For the HTML above, you decide you want this component interface:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">anchored-heading</span> <span class="attr">:level</span>=<span class="string">"1"</span>&gt;</span>Hello world!<span class="tag">&lt;/<span class="name">anchored-heading</span>&gt;</span></div></pre></td></tr></table></figure>
<p>When you get started with a component that just generates a heading based on the <code>level</code> prop, you quickly arrive at this:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/x-template"</span> <span class="attr">id</span>=<span class="string">"anchored-heading-template"</span>&gt;</span><span class="xml"></span></div><div class="line">  <span class="tag">&lt;<span class="name">div</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">h1</span> <span class="attr">v-if</span>=<span class="string">"level === 1"</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">h2</span> <span class="attr">v-if</span>=<span class="string">"level === 2"</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">h2</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">h3</span> <span class="attr">v-if</span>=<span class="string">"level === 3"</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">h3</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">h4</span> <span class="attr">v-if</span>=<span class="string">"level === 4"</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">h4</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">h5</span> <span class="attr">v-if</span>=<span class="string">"level === 5"</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">h5</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">h6</span> <span class="attr">v-if</span>=<span class="string">"level === 6"</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">h6</span>&gt;</span></div><div class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></div></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">Vue.component(<span class="string">'anchored-heading'</span>, &#123;</div><div class="line">  template: <span class="string">'#anchored-heading-template'</span>,</div><div class="line">  props: &#123;</div><div class="line">    level: &#123;</div><div class="line">      type: <span class="built_in">Number</span>,</div><div class="line">      required: <span class="literal">true</span></div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>That template doesn’t feel great. It’s not only verbose, but we’re duplicating <code>&lt;slot&gt;&lt;/slot&gt;</code> for every heading level and will have to do the same when we add the anchor element. The whole thing is also wrapped in a useless <code>div</code> because components must contain exactly one root node.</p>
<p>While templates work great for most components, it’s clear that this isn’t one of them. So let’s try rewriting it with a <code>render</code> function:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">Vue.component(<span class="string">'anchored-heading'</span>, &#123;</div><div class="line">  render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement</span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> createElement(</div><div class="line">      <span class="string">'h'</span> + <span class="keyword">this</span>.level,   <span class="comment">// tag name</span></div><div class="line">      <span class="keyword">this</span>.$slots.default <span class="comment">// array of children</span></div><div class="line">    )</div><div class="line">  &#125;,</div><div class="line">  props: &#123;</div><div class="line">    level: &#123;</div><div class="line">      type: <span class="built_in">Number</span>,</div><div class="line">      required: <span class="literal">true</span></div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>Much simpler! Sort of. The code is shorter, but also requires greater familiarity with Vue instance properties. In this case, you have to know that when you pass children without a <code>slot</code> attribute into a component, like the <code>Hello world!</code> inside of <code>anchored-heading</code>, those children are stored on the component instance at <code>$slots.default</code>. If you haven’t already, <strong>it’s recommended to read through the <a href="/api/#vm-slots">instance properties API</a> before diving into render functions.</strong></p>
<h2 id="createElement-Arguments"><a href="#createElement-Arguments" class="headerlink" title="createElement Arguments"></a><code>createElement</code> Arguments</h2><p>The second thing you’ll have to become familiar with is how to use template features in the <code>createElement</code> function. Here are the arguments that <code>createElement</code> accepts:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="comment">// @returns &#123;VNode&#125;</span></div><div class="line">createElement(</div><div class="line">  <span class="comment">// &#123;String | Object | Function&#125;</span></div><div class="line">  <span class="comment">// An HTML tag name, component options, or function</span></div><div class="line">  <span class="comment">// returning one of these. Required.</span></div><div class="line">  <span class="string">'div'</span>,</div><div class="line"></div><div class="line">  <span class="comment">// &#123;Object&#125;</span></div><div class="line">  <span class="comment">// A data object corresponding to the attributes</span></div><div class="line">  <span class="comment">// you would use in a template. Optional.</span></div><div class="line">  &#123;</div><div class="line">    <span class="comment">// (see details in the next section below)</span></div><div class="line">  &#125;,</div><div class="line"></div><div class="line">  <span class="comment">// &#123;String | Array&#125;</span></div><div class="line">  <span class="comment">// Children VNodes. Optional.</span></div><div class="line">  [</div><div class="line">    createElement(<span class="string">'h1'</span>, <span class="string">'hello world'</span>)</div><div class="line">    createElement(MyComponent, &#123;</div><div class="line">      props: &#123;</div><div class="line">        someProp: <span class="string">'foo'</span></div><div class="line">      &#125;</div><div class="line">    &#125;),</div><div class="line">    <span class="string">'bar'</span></div><div class="line">  ]</div><div class="line">)</div></pre></td></tr></table></figure>
<h3 id="The-Data-Object-In-Depth"><a href="#The-Data-Object-In-Depth" class="headerlink" title="The Data Object In-Depth"></a>The Data Object In-Depth</h3><p>One thing to note: similar to how <code>v-bind:class</code> and <code>v-bind:style</code> have special treatment in templates, they have their own top-level fields in VNode data objects.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">&#123;</div><div class="line">  <span class="comment">// Same API as `v-bind:class`</span></div><div class="line">  <span class="string">'class'</span>: &#123;</div><div class="line">    foo: <span class="literal">true</span>,</div><div class="line">    bar: <span class="literal">false</span></div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// Same API as `v-bind:style`</span></div><div class="line">  style: &#123;</div><div class="line">    color: <span class="string">'red'</span>,</div><div class="line">    fontSize: <span class="string">'14px'</span></div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// Normal HTML attributes</span></div><div class="line">  attrs: &#123;</div><div class="line">    id: <span class="string">'foo'</span></div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// Component props</span></div><div class="line">  props: &#123;</div><div class="line">    myProp: <span class="string">'bar'</span></div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// DOM properties</span></div><div class="line">  domProps: &#123;</div><div class="line">    innerHTML: <span class="string">'baz'</span></div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// Event handlers are nested under "on", though</span></div><div class="line">  <span class="comment">// modifiers such as in v-on:keyup.enter are not</span></div><div class="line">  <span class="comment">// supported. You'll have to manually check the</span></div><div class="line">  <span class="comment">// keyCode in the handler instead.</span></div><div class="line">  on: &#123;</div><div class="line">    click: <span class="keyword">this</span>.clickHandler</div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// For components only. Allows you to listen to</span></div><div class="line">  <span class="comment">// native events, rather than events emitted from</span></div><div class="line">  <span class="comment">// the component using vm.$emit.</span></div><div class="line">  nativeOn: &#123;</div><div class="line">    click: <span class="keyword">this</span>.nativeClickHandler</div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// Other special top-level properties</span></div><div class="line">  key: <span class="string">'myKey'</span>,</div><div class="line">  ref: <span class="string">'myRef'</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="Complete-Example"><a href="#Complete-Example" class="headerlink" title="Complete Example"></a>Complete Example</h3><p>With this knowledge, we can now finish the component we started:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="keyword">var</span> getChildrenTextContent = <span class="function"><span class="keyword">function</span> (<span class="params">children</span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> children.map(<span class="function"><span class="keyword">function</span> (<span class="params">node</span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> node.children</div><div class="line">      ? getChildrenTextContent(node.children)</div><div class="line">      : node.text</div><div class="line">  &#125;).join(<span class="string">''</span>)</div><div class="line">&#125;</div><div class="line"></div><div class="line">Vue.component(<span class="string">'anchored-heading'</span>, &#123;</div><div class="line">  render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement</span>) </span>&#123;</div><div class="line">    <span class="comment">// create kebabCase id</span></div><div class="line">    <span class="keyword">var</span> headingId = getChildrenTextContent(<span class="keyword">this</span>.$slots.default)</div><div class="line">      .toLowerCase()</div><div class="line">      .replace(<span class="regexp">/\W+/g</span>, <span class="string">'-'</span>)</div><div class="line">      .replace(<span class="regexp">/(^\-|\-$)/g</span>, <span class="string">''</span>)</div><div class="line"></div><div class="line">    <span class="keyword">return</span> createElement(</div><div class="line">      <span class="string">'h'</span> + <span class="keyword">this</span>.level,</div><div class="line">      [</div><div class="line">        createElement(<span class="string">'a'</span>, &#123;</div><div class="line">          attrs: &#123;</div><div class="line">            name: headingId,</div><div class="line">            href: <span class="string">'#'</span> + headingId</div><div class="line">          &#125;</div><div class="line">        &#125;, <span class="keyword">this</span>.$slots.default)</div><div class="line">      ]</div><div class="line">    )</div><div class="line">  &#125;,</div><div class="line">  props: &#123;</div><div class="line">    level: &#123;</div><div class="line">      type: <span class="built_in">Number</span>,</div><div class="line">      required: <span class="literal">true</span></div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<h3 id="Constraints"><a href="#Constraints" class="headerlink" title="Constraints"></a>Constraints</h3><h4 id="VNodes-Must-Be-Unique"><a href="#VNodes-Must-Be-Unique" class="headerlink" title="VNodes Must Be Unique"></a>VNodes Must Be Unique</h4><p>All VNodes in the component tree must be unique. That means the following render function is invalid:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement</span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> myParagraphVNode = createElement(<span class="string">'p'</span>, <span class="string">'hi'</span>)</div><div class="line">  <span class="keyword">return</span> createElement(<span class="string">'div'</span>, [</div><div class="line">    <span class="comment">// Yikes - duplicate VNodes!</span></div><div class="line">    myParagraphVNode, myParagraphVNode</div><div class="line">  ])</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>If you really want to duplicate the same element/component many times, you can do so with a factory function. For example, the following render function is a perfectly valid way of rendering 20 identical paragraphs:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement</span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> myParagraph =</div><div class="line">  <span class="keyword">return</span> createElement(<span class="string">'div'</span>,</div><div class="line">    <span class="built_in">Array</span>.apply(<span class="literal">null</span>, &#123; length: <span class="number">20</span> &#125;).map(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">      <span class="keyword">return</span> createElement(<span class="string">'p'</span>, <span class="string">'hi'</span>)</div><div class="line">    &#125;)</div><div class="line">  )</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="Replacing-Template-Features-with-Plain-JavaScript"><a href="#Replacing-Template-Features-with-Plain-JavaScript" class="headerlink" title="Replacing Template Features with Plain JavaScript"></a>Replacing Template Features with Plain JavaScript</h2><p>Wherever something can be easily accomplished in plain JavaScript, Vue render functions do not provide a proprietary alternative. For example, in a template using <code>v-if</code> and <code>v-for</code>:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">v-if</span>=<span class="string">"items.length"</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-for</span>=<span class="string">"item in items"</span>&gt;</span>&#123;&#123; item.name &#125;&#125;<span class="tag">&lt;/<span class="name">li</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">v-else</span>&gt;</span>No items found.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></div></pre></td></tr></table></figure>
<p>This could be rewritten with JavaScript’s <code>if</code>/<code>else</code> and <code>map</code> in a render function:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement</span>) </span>&#123;</div><div class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.items.length) &#123;</div><div class="line">    <span class="keyword">return</span> createElement(<span class="string">'ul'</span>, <span class="keyword">this</span>.items.map(<span class="function"><span class="keyword">function</span> (<span class="params">item</span>) </span>&#123;</div><div class="line">      <span class="keyword">return</span> createElement(<span class="string">'li'</span>, item.name)</div><div class="line">    &#125;))</div><div class="line">  &#125; <span class="keyword">else</span> &#123;</div><div class="line">    <span class="keyword">return</span> createElement(<span class="string">'p'</span>, <span class="string">'No items found.'</span>)</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="JSX"><a href="#JSX" class="headerlink" title="JSX"></a>JSX</h2><p>If you’re writing a lot of <code>render</code> functions, it might feel painful that we’re using 14 lines above in place of this much simpler and arguably more readable template:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">anchored-heading</span> <span class="attr">:level</span>=<span class="string">"1"</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">span</span>&gt;</span>Hello<span class="tag">&lt;/<span class="name">span</span>&gt;</span> world!</div><div class="line"><span class="tag">&lt;/<span class="name">anchored-heading</span>&gt;</span></div></pre></td></tr></table></figure>
<p>That’s why there’s a <a href="https://github.com/vuejs/babel-plugin-transform-vue-jsx" target="_blank" rel="external">Babel plugin</a> to use JSX with Vue, getting us back to a syntax that’s closer to templates:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="keyword">import</span> AnchoredHeading <span class="keyword">from</span> <span class="string">'./AnchoredHeading.vue'</span></div><div class="line"></div><div class="line"><span class="keyword">new</span> Vue(&#123;</div><div class="line">  el: <span class="string">'#demo'</span>,</div><div class="line">  render (h) &#123;</div><div class="line">    <span class="keyword">return</span> (</div><div class="line">      <span class="xml"><span class="tag">&lt;<span class="name">AnchoredHeading</span> <span class="attr">level</span>=<span class="string">&#123;1&#125;</span>&gt;</span></span></div><div class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>Hello<span class="tag">&lt;/<span class="name">span</span>&gt;</span> world!</div><div class="line">      <span class="tag">&lt;/<span class="name">AnchoredHeading</span>&gt;</span></div><div class="line">    )</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p class="tip">Aliasing <code>createElement</code> to <code>h</code> is a common convention you’ll see in the Vue ecosystem and is actually required for JSX. If <code>h</code> is not available in the scope, your app will throw an error.</p>

<p>For more on how JSX maps to JavaScript, see the <a href="https://github.com/vuejs/babel-plugin-transform-vue-jsx#usage" target="_blank" rel="external">usage docs</a>.</p>
<h2 id="Functional-Components"><a href="#Functional-Components" class="headerlink" title="Functional Components"></a>Functional Components</h2><p>The anchored heading component we created earlier is relatively simple. It doesn’t manage any state, watch any state passed to it, and it has no lifecycle methods. Really, it’s just a function with some props.</p>
<p>In cases like this, we can mark components as <code>functional</code>, which means that they’re stateless (no <code>data</code>) and instanceless (no <code>this</code> context). A <strong>functional component</strong> looks like this:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line">Vue.component(<span class="string">'my-component'</span>, &#123;</div><div class="line">  functional: <span class="literal">true</span>,</div><div class="line">  <span class="comment">// To compensate for the lack of an instance,</span></div><div class="line">  <span class="comment">// we are now provided a 2nd context argument.</span></div><div class="line">  render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement, context</span>) </span>&#123;</div><div class="line">    <span class="comment">// ...</span></div><div class="line">  &#125;,</div><div class="line">  <span class="comment">// Props are optional</span></div><div class="line">  props: &#123;</div><div class="line">    <span class="comment">// ...</span></div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>Everything the component needs is passed through <code>context</code>, which is an object containing:</p>
<ul>
<li><code>props</code>: An object of the provided props</li>
<li><code>children</code>: An array of the VNode children</li>
<li><code>slots</code>: A function returning a slots object</li>
<li><code>data</code>: The entire data object passed to the component</li>
<li><code>parent</code>: A reference to the parent component</li>
</ul>
<p>After adding <code>functional: true</code>, updating the render function of our anchored heading component would simply require adding the <code>context</code> argument, updating <code>this.$slots.default</code> to <code>context.children</code>, then updating <code>this.level</code> to <code>context.props.level</code>.</p>
<p>Since functional components are just functions, they’re much cheaper to render. They’re also very useful as wrapper components. For example, when you need to:</p>
<ul>
<li>Programmatically choose one of several other components to delegate to</li>
<li>Manipulate children, props, or data before passing them on to a child component</li>
</ul>
<p>Here’s an example of a <code>smart-list</code> component that delegates to more specific components, depending on the props passed to it:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><div class="line"><span class="keyword">var</span> EmptyList = &#123; <span class="comment">/* ... */</span> &#125;</div><div class="line"><span class="keyword">var</span> TableList = &#123; <span class="comment">/* ... */</span> &#125;</div><div class="line"><span class="keyword">var</span> OrderedList = &#123; <span class="comment">/* ... */</span> &#125;</div><div class="line"><span class="keyword">var</span> UnorderedList = &#123; <span class="comment">/* ... */</span> &#125;</div><div class="line"></div><div class="line">Vue.component(<span class="string">'smart-list'</span>, &#123;</div><div class="line">  functional: <span class="literal">true</span>,</div><div class="line">  render: <span class="function"><span class="keyword">function</span> (<span class="params">createElement, context</span>) </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">appropriateListComponent</span> (<span class="params"></span>) </span>&#123;</div><div class="line">      <span class="keyword">var</span> items = context.props.items</div><div class="line"></div><div class="line">      <span class="keyword">if</span> (items.length === <span class="number">0</span>)           <span class="keyword">return</span> EmptyList</div><div class="line">      <span class="keyword">if</span> (<span class="keyword">typeof</span> items[<span class="number">0</span>] === <span class="string">'object'</span>) <span class="keyword">return</span> TableList</div><div class="line">      <span class="keyword">if</span> (context.props.isOrdered)      <span class="keyword">return</span> OrderedList</div><div class="line"></div><div class="line">      <span class="keyword">return</span> UnorderedList</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> createElement(</div><div class="line">      appropriateListComponent(),</div><div class="line">      context.data,</div><div class="line">      context.children</div><div class="line">    )</div><div class="line">  &#125;,</div><div class="line">  props: &#123;</div><div class="line">    items: &#123;</div><div class="line">      type: <span class="built_in">Array</span>,</div><div class="line">      required: <span class="literal">true</span></div><div class="line">    &#125;,</div><div class="line">    isOrdered: <span class="built_in">Boolean</span></div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<h3 id="slots-vs-children"><a href="#slots-vs-children" class="headerlink" title="slots() vs children"></a><code>slots()</code> vs <code>children</code></h3><p>You may wonder why we need both <code>slots()</code> and <code>children</code>. Wouldn’t <code>slots().default</code> be the same as <code>children</code>? In some cases, yes - but what if you have a functional component with the following children?</p>
<figure class="highlight html"><table><tr><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">my-functional-component</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">p</span> <span class="attr">slot</span>=<span class="string">"foo"</span>&gt;</span></div><div class="line">    first</div><div class="line">  <span class="tag">&lt;/<span class="name">p</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>second<span class="tag">&lt;/<span class="name">p</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">my-functional-component</span>&gt;</span></div></pre></td></tr></table></figure>
<p>For this component, <code>children</code> will give you both paragraphs, <code>slots().default</code> will give you only the second, and <code>slots().foo</code> will give you only the first. Having both <code>children</code> and <code>slots()</code> therefore allows you to choose whether this component knows about a slot system or perhaps delegates that responsibility to another component by simply passing along <code>children</code>.</p>
<h2 id="Template-Compilation"><a href="#Template-Compilation" class="headerlink" title="Template Compilation"></a>Template Compilation</h2><p>You may be interested to know that Vue’s templates actually compile to render functions. This is an implementation detail you usually don’t need to know about, but if you’d like to see how specific template features are compiled, you may find it interesting. Below is a little demo using <code>Vue.compile</code> to live-compile a template string:</p>

<div id="vue-compile-demo" class="demo">
  <textarea v-model="templateText" rows="10"></textarea>
  <div v-if="typeof result === 'object'">
    <label>render:</label>
    <pre><code>{{ result.render }}</code></pre>
    <label>staticRenderFns:</label>
    <pre v-for="(fn, index) in result.staticRenderFns"><code>_m({{ index }}): {{ fn }}</code></pre>
  </div>
  <div v-else="">
    <label>Compilation Error:</label>
    <pre><code>{{ result }}</code></pre>
  </div>
</div>
<script>
new Vue({
  el: '#vue-compile-demo',
  data: {
    templateText: '\
<div>\n\
  <h1>I\'m a template!</h1>\n\
  <p v-if="message">\n\
    {{ message }}\n\
  </p>\n\
  <p v-else>\n\
    No message.\n\
  </p>\n\
</div>\
    ',
  },
  computed: {
    result: function () {
      if (!this.templateText) {
        return 'Enter a valid template above'
      }
      try {
        var result = Vue.compile(this.templateText.replace(/\s{2,}/g, ''))
        return {
          render: this.formatFunction(result.render),
          staticRenderFns: result.staticRenderFns.map(this.formatFunction)
        }
      } catch (error) {
        return error.message
      }
    }
  },
  methods: {
    formatFunction: function (fn) {
      return fn.toString().replace(/(\{\n)(\S)/, '$1  $2')
    }
  }
})
console.error = function (error) {
  throw new Error(error)
}
</script>
<style>
#vue-compile-demo pre {
  padding: 10px;
  overflow-x: auto;
}
#vue-compile-demo code {
  white-space: pre;
  padding: 0
}
#vue-compile-demo textarea {
  width: 100%;

}
</style>


    
      <div class="guide-links">
        
          <span>← <a href="/guide/transitioning-state.html">Transitioning State</a></span>
        
        
          <span style="float:right"><a href="/guide/reactivity.html">Reactivity in Depth</a> →</span>
        
      </div>
    
    <div class="footer">
      Caught a mistake or want to contribute to the documentation?
      <a href="https://github.com/vuejs/vuejs.org/blob/master/src/guide/render-function.md" target="_blank">
        Edit this page on Github!
      </a>
    </div>
</div>

                
            </div>
            <script src="//cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
            <script src="/js/smooth-scroll.min.js"></script>
            <script src="/js/common.js"></script>
        

        <script src="//cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script><script src="https://cdn.jsdelivr.net/gh/shentao/vuejs-outdated-docs-modal@v1.3/prompt.min.js"></script>
        <script>
            document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
            }, false);
        </script>
    </body>
</html>
